/**
 * Copyright 2008 Mathias Doenitz, http://lis.to/
 *
 * This file is part of the lis.to java desktop client. The lis.to java desktop client is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * The lis.to java desktop client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with the lis.to java desktop client.
 * If not, see http://www.gnu.org/licenses/
 */

package listo.utils.swing;

import listo.utils.MiscUtils;
import org.apache.commons.lang.StringUtils;

import javax.swing.*;
import javax.swing.plaf.basic.BasicLabelUI;
import java.awt.*;

public class HyperlinkLabelUI extends BasicLabelUI {

    public static HyperlinkLabelUI instance = new HyperlinkLabelUI();

    private HyperlinkLabelUI() {
    }

    protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) {
        HyperlinkLabel label = (HyperlinkLabel) l;

        doLayout(label, textX, textY);

        FontMetrics fm = label.getFontMetrics(label.getFont());

        MiscUtils.UrlMatch[] urlMatches = label.getUrlMatches();
        if (urlMatches != null) {
            String text = label.getText();
            int start = 0;
            for (int i = 0; i < urlMatches.length; i++) {
                MiscUtils.UrlMatch urlMatch = urlMatches[i];
                // draw the "normal" text before the current link
                String drawText = text.substring(start, urlMatch.startIndex);
                if (StringUtils.isNotEmpty(drawText)) {
                    super.paintEnabledText(l, g, drawText, textX, textY);
                    textX += fm.stringWidth(drawText);
                }

                // draw the current link
                drawText = text.substring(urlMatch.startIndex, urlMatch.endIndex);
                label.setPaintingLink(true);
                if (StringUtils.isNotEmpty(drawText)) {
                    // draw the link text
                    super.paintEnabledText(l, g, drawText, textX, textY);
                    int linkWidth = fm.stringWidth(drawText);

                    // draw the underline if required
                    if (label.isForceUnderline() || label.getOverLink() == i) {
                        g.setColor(label.getLinkColor());
                        int baseline = (int) (textY + Math.ceil(fm.getLineMetrics(s, g).getUnderlineOffset()));
                        g.drawLine(textX, baseline, textX + linkWidth, baseline);
                    }

                    textX += linkWidth;
                }
                label.setPaintingLink(false);
                start = urlMatch.endIndex;
            }

            // draw the remaining "normal" text if there is some
            if (start < text.length()) {
                String drawText = text.substring(start);
                super.paintEnabledText(l, g, drawText, textX, textY);
                textX += fm.stringWidth(drawText);
            }
        } else {
            // just delegate to super
            super.paintEnabledText(l, g, s, textX, textY);
            textX += fm.stringWidth(s);
        }

        // strike through if required
        if (label.isStrikeThrough()) {
            g.setColor(label.getForeground());
            int line = (int) (textY + Math.ceil(fm.getLineMetrics(s, g).getStrikethroughOffset()));
            g.drawLine(0, line, textX, line);
        }
    }

    public void doLayout(HyperlinkLabel label, int textX, int textY) {
        MiscUtils.UrlMatch[] urlMatches = label.getUrlMatches();
        if (urlMatches == null) {
            label.setLinkBounds(null);
            return;
        }

        FontMetrics fm = label.getFontMetrics(label.getFont());
        Rectangle[] linkBounds = new Rectangle[urlMatches.length];

        String text = label.getText();
        int start = 0;
        for (int i = 0; i < urlMatches.length; i++) {
            MiscUtils.UrlMatch urlMatch = urlMatches[i];
            // layout the "normal" text before the current link
            String drawText = text.substring(start, urlMatch.startIndex);
            if (StringUtils.isNotEmpty(drawText)) textX += fm.stringWidth(drawText);

            // layout the current link
            drawText = text.substring(urlMatch.startIndex, urlMatch.endIndex);
            if (StringUtils.isNotEmpty(drawText)) {
                int linkWidth = fm.stringWidth(drawText);
                linkBounds[i] = new Rectangle(textX, textY - Math.round(fm.getHeight()) + 1, linkWidth,
                        Math.round(fm.getHeight()) + 2);
                textX += linkWidth;
            }
            start = urlMatch.endIndex;
        }

        label.setLinkBounds(linkBounds);
    }

}
